package com.google.code.maven.instrument.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.logging.SystemStreamLog;

public final class ClassFileLocator {

	Log log = null;

	public ClassFileLocator() {
	}

	public Collection<ClassFile> findClasses(final File targetDir) {
		if (!targetDir.isDirectory()) {
			throw new IllegalArgumentException(
					"targetDir must be a directory: " + targetDir);
		}

		return recursivelyFindClasses(targetDir);
	}

	private Collection<ClassFile> recursivelyFindClasses(final File targetDir) {
		final FileFilter directoryFilter = FileFilterUtils
				.directoryFileFilter();
		final File[] subDirs = targetDir.listFiles(directoryFilter);
		final ArrayList<ClassFile> classesFound = new ArrayList<ClassFile>();
		for (final File subDir : subDirs) {
			classesFound.addAll(recursivelyFindClasses(subDir));
		}

		classesFound.addAll(findClassFilesInDirectory(targetDir));

		return classesFound;
	}

	private Collection<? extends ClassFile> findClassFilesInDirectory(
			final File directory) {

		final FileFilter classNameFilter = new ClassFileFilter();
		final File[] classFiles = directory.listFiles(classNameFilter);

		final Collection<ClassFile> classesFound = new ArrayList<ClassFile>();

		for (final File file : classFiles) {
			ClassFile classFile;
			try {
				classFile = new ClassFile(file);
				classesFound.add(classFile);
			} catch (final IOException e) {
				getLog().warn(
						"Failed to read in file: " + file
								+ ", it will be ignored.", e);
			}
		}
		return classesFound;
	}

	/**
	 * Dependency Injection
	 */
	public void setLog(final Log log) {
		this.log = log;
	}

	public Log getLog() {
		if (log == null) {
			log = new SystemStreamLog();
		}

		return log;
	}

}
